
package org.dromara.common.core.threads;


import org.springframework.core.task.TaskDecorator;

import java.util.concurrent.*;

public class ExecutorFactory {

    public static ExecutorService newThreadPool(int minThreads, int maxThreads, long maxIdleTime, TimeUnit unit) {
        return newThreadPool(minThreads, maxThreads, maxIdleTime, unit, 5, TimeUnit.MINUTES, null);
    }

    public static ExecutorService newThreadPool(int minThreads, int maxThreads, long maxIdleTime, TimeUnit unit, TaskDecorator taskDecorator) {
        return newThreadPool(minThreads, maxThreads, maxIdleTime, unit, 5, TimeUnit.MINUTES, taskDecorator);
    }

    public static ExecutorService newThreadPool(int minThreads, int maxThreads, long maxIdleTime, TimeUnit unit, long threadRunTime, TimeUnit threadRunTimUnit, TaskDecorator taskDecorator) {
        TaskQueue taskqueue = new TaskQueue();
        ThreadFactory threadFactory = new TaskThreadFactory("task", true, Thread.NORM_PRIORITY);
        ThreadPoolExecutor service = new TribesThreadPoolExecutor(minThreads, maxThreads, maxIdleTime, unit, taskqueue, threadFactory, threadRunTime, threadRunTimUnit);
        service.setTaskDecorator(taskDecorator);
        taskqueue.setParent(service);
        return service;
    }

    public static ExecutorService newThreadPool(int minThreads, int maxThreads, long maxIdleTime, TimeUnit unit, ThreadFactory threadFactory) {
        return newThreadPool(minThreads, maxThreads, maxIdleTime, unit, threadFactory, 5, TimeUnit.MINUTES, null);
    }

    public static ExecutorService newThreadPool(int minThreads, int maxThreads, long maxIdleTime, TimeUnit unit, ThreadFactory threadFactory, long threadRunTime,
                                                TimeUnit threadRunTimUnit, TaskDecorator taskDecorator) {
        TaskQueue taskqueue = new TaskQueue();
        ThreadPoolExecutor service = new TribesThreadPoolExecutor(minThreads, maxThreads, maxIdleTime, unit, taskqueue, threadFactory, threadRunTime, threadRunTimUnit);
        service.setTaskDecorator(taskDecorator);
        taskqueue.setParent(service);

        return service;
    }

    // ---------------------------------------------- TribesThreadPoolExecutor Inner Class
    private static class TribesThreadPoolExecutor extends ThreadPoolExecutor {
        public TribesThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
        }

        public TribesThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
                                        RejectedExecutionHandler handler, long threadRunTime,
                                        TimeUnit threadRunTimUnit) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler, threadRunTime, threadRunTimUnit);
        }

        public TribesThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, long threadRunTime,
                                        TimeUnit threadRunTimUnit) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, threadRunTime, threadRunTimUnit);
        }

        public TribesThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        }

        @Override
        public void execute(Runnable command) {
            try {
                super.execute(command);
            } catch (RejectedExecutionException rx) {
                if (super.getQueue() instanceof TaskQueue) {
                    TaskQueue queue = (TaskQueue) super.getQueue();
                    if (!queue.force(command)) {
                        throw new RejectedExecutionException("Queue capacity is full.");
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        ExecutorService executorService = ExecutorFactory.newThreadPool(1, 200, 60, TimeUnit.SECONDS, 20, TimeUnit.MILLISECONDS, null);
        for (int i = 0; i < 10000000; i++) {
            Future future = executorService.submit(new Runnable() {
                @Override
                public void run() {
                    for (long i = 0; i < 1000L; i++) {
                        try {
                            Thread.sleep(3, 3);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            break;
                        }
                    }

//                    Thread
                    System.out.println(Thread.currentThread().getName());

                }
            });
        }

        try {
            Thread.sleep(2000000000L);
        } catch (InterruptedException e) {

        }
    }
}
